package com.mytijian.code.service;

import com.alibaba.fastjson.JSON;
import com.mytijian.code.enums.CodeOperateEnum;
import com.mytijian.code.enums.ExpireStatusEnum;
import com.mytijian.code.enums.MerchantOrderStatusEnum;
import com.mytijian.code.enums.SendCodeStatusEnum;
import com.mytijian.code.exceptions.MashangExceptionEnum;
import com.mytijian.code.model.Mcode;
import com.mytijian.code.model.MerchantOrder;
import com.mytijian.code.param.ModifyValidityParam;
import com.mytijian.code.param.ReSendParam;
import com.mytijian.code.param.SendParam;
import com.mytijian.code.service.helper.ExecutorServiceHelper;
import com.mytijian.code.service.helper.ToTaobaoHelper;
import com.mytijian.code.service.helper.TransactionHelper;
import com.mytijian.code.service.utils.MerchantOrderUtil;
import com.mytijian.exception.BizException;
import com.mytijian.exception.BizSystemException;
import com.mytijian.utils.BeanUtil;
import com.mytijian.utils.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SendCodeServiceImpl implements SendCodeService {

    private Logger logger = LoggerFactory.getLogger(SendCodeServiceImpl.class);

    @Autowired
    private MerchantOrderService merchantOrderService;
    @Autowired
    private CodeService codeService;
    @Autowired
    private CodeOperateLogService codeOperateLogService;
    @Autowired
    private ToTaobaoHelper toTaobaoHelper;
    @Autowired
    private TransactionHelper transactionHelper;
    @Autowired
    private MerchantOrderSendCodeLifeCycle merchantOrderSendCodeLifeCycle;
    @Autowired
    private ExecutorServiceHelper executorServiceHelper;

    @Override
    public void acceptSend(SendParam param) {
        logger.info("发码开始param: {}", JSON.toJSONString(param));
        //校验参数
        validateSendParam(param);
        //查询订单是否存在
        MerchantOrder orderExist = merchantOrderService.selectByOuterId(param.getOuterId());
        if (orderExist != null) {
            return;
        }
        //存储订单信息到天猫订单信息表
        MerchantOrder order = BeanUtil.createObject(param, MerchantOrder.class);
        order.setSendCodeStatus(SendCodeStatusEnum.UN_SEND.getCode());
        order.setSendCodeIsSuccess(false);
        order.setStatus(MerchantOrderStatusEnum.NORMAL.getCode());
        merchantOrderService.saveOrder(order);
        //启动发码线程
		executorServiceHelper.submit(() -> sendCode(order));
        logger.info("发码通知结束outerId={}", param.getOuterId());
    }

    /**
     * 校验参数
     * @param param
     */
    private void validateSendParam(SendParam param) {
        if (StringUtils.isBlank(param.getOuterIdSKU())) {
            throw new BizException(MashangExceptionEnum.OUTERIDSKU_CANNOT_EMPTY);
        }
    }

    @Override
    public void acceptResend(ReSendParam param) {
        logger.info("重新发码通知param: {}", JSON.toJSONString(param));
        
        MerchantOrder order = merchantOrderService.selectByOuterId(param.getOuterId());
        validOrderSendCodeStatus(order);
        //设置订单待重发
//        merchantOrderSendCodeLifeCycle.unResendCode(order.getId());
        order.setSendCodeStatus(SendCodeStatusEnum.UN_RESEND.getCode());
        order.setAvailableNum(param.getAvailableNum());
        merchantOrderService.updateTmOrder(order, null);

		// 启动重新发码线程
		executorServiceHelper.submit(() -> resendCode(order));
        logger.info("重新发码通知结束outerId={}", param.getOuterId());
    }

	private void validOrderSendCodeStatus(MerchantOrder order) {
		if (order == null) {
            throw new BizException(MashangExceptionEnum.ORDER_NOT_EXIST);
        }
        if (order.getSendCodeStatus() == SendCodeStatusEnum.UN_SEND.getCode()) {
            throw new BizException(MashangExceptionEnum.ORDER_STATUS_CANNOT_RESEND);
        }
	}

    @Override
    public void sendCode(MerchantOrder order) {
        logger.info("发码开始 outerId={}, param: {}", order.getOuterId(), JSON.toJSONString(order));
        // 校验订单是否满足发码条件
        validateSendcodeOrder(order);
        // 发码
        List<Mcode> mcodes = Collections.emptyList();
        // 开启事务
        TransactionStatus status = transactionHelper.beginTransaction();
        try {
            // 创建码
            mcodes = codeService.saveMcodes(order);
            // 创建码日志
            codeOperateLogService.saveCodeOperateLogs(mcodes, CodeOperateEnum.SEND_CODE);
            // 订单发码完成
            merchantOrderSendCodeLifeCycle.finishSendCode(order.getId(), SendCodeStatusEnum.UN_SEND.getCode());
            // 提交事务
            transactionHelper.commit(status);
        } catch (Exception ex) {
            logger.error("发码异常,数据回滚,outerId={}", order.getOuterId(), ex);
            // 事务回滚
            transactionHelper.rollback(status);
            throw new BizSystemException(MashangExceptionEnum.SYSTEM_ERROR, ex);
        }
        // 通知码商平台
        sendNotifyCodeMerchantPlatform(order, mcodes);
        logger.info("发码结束 outerId={}", order.getOuterId());
    }

    private void validateSendcodeOrder(MerchantOrder order) {
        if (order.getSendCodeStatus() != SendCodeStatusEnum.UN_SEND.getCode()) {
            logger.info("订单[id={}]状态[status={}]不满足发码条件", order.getId(), order.getSendCodeStatus());
            throw new BizException(MashangExceptionEnum.ORDER_STATUS_CANNOT_SEND_CODE);
        }
    }

    private void sendNotifyCodeMerchantPlatform(MerchantOrder order, List<Mcode> mcodes) {
        // 通知码商平台
        toTaobaoHelper.send(order, mcodes);
        // 更新订单发码成功
        merchantOrderService.orderSendCodeNotifySuccess(order.getId());
    }

    @Override
    public void reissueSendCode() {

        List<MerchantOrder> needSendCodeOrders = merchantOrderService.listNeedSendCodeOrders();
        // 需要新建码的订单
        List<MerchantOrder> needNewCodeOrders = getNeedNewCodeOrders(needSendCodeOrders);
        sendCode(needNewCodeOrders);
        // 需要重新发码的的订单
        List<MerchantOrder> needReSendCodeOrders = getNeedReSendCodeOrders(needSendCodeOrders);
        resendCode(needReSendCodeOrders);
        // 通知码商平台失败，需要重新通知码商平台订单
        List<MerchantOrder> needNotifyOrders = getNeedNotifyMerchantOrders(needSendCodeOrders);
        notifyCodeMerchantPlatform(needNotifyOrders);
    }

    private void notifyCodeMerchantPlatform(List<MerchantOrder> needNotifyOrders) {
        // 获取发码通知订单
        List<MerchantOrder> needNewCodeOrders = getMerchantOrdersBySendCodeStatus(needNotifyOrders,
                SendCodeStatusEnum.SEND);
        for (MerchantOrder order : needNewCodeOrders) {
            try {
                List<Mcode> codes = codeService.listMcodeByOuterId(order.getOuterId());
                sendNotifyCodeMerchantPlatform(order, codes);
            } catch (Exception ex) {
                logger.error("订单[outId={},id={}]发码通知失败：", order.getOuterId(), order.getId(), ex);
            }
        }
        // 获取重新发码通知订单
        List<MerchantOrder> needReSendCodeOrders = getMerchantOrdersBySendCodeStatus(needNotifyOrders,
                SendCodeStatusEnum.RESEND);
        for (MerchantOrder order : needReSendCodeOrders) {
            try {
                List<Mcode> codes = codeService.listMcodeByOuterId(order.getOuterId());
                resendNotifyCodeMerchantPlatform(order, codes);
            } catch (Exception ex) {
                logger.error("订单[outId={},id={}]重新发码通知失败：", order.getOuterId(), order.getId(), ex);
            }
        }
    }

    /**
     * 发码接口
     */
    private void sendCode(List<MerchantOrder> merchantOrders) {
        for (MerchantOrder order : merchantOrders) {
            try {
                sendCode(order);
            } catch (Exception ex) {
                logger.error("订单[outId={},id={}]发码失败：", order.getOuterId(), order.getId(), ex);
            }
        }
    }

    /**
     * 重新发码接口
     */
    private void resendCode(List<MerchantOrder> merchantOrders) {
        for (MerchantOrder order : merchantOrders) {
            try {
                resendCode(order);
            } catch (Exception ex) {
                logger.error("订单[outId={},id={}]重新发码失败：", order.getOuterId(), order.getId(), ex);
            }
        }
    }

    private List<MerchantOrder> getNeedNotifyMerchantOrders(List<MerchantOrder> merchantOrders) {
        if (CollectionUtils.isEmpty(merchantOrders)) {
            return Collections.emptyList();
        }
        return merchantOrders
                .stream()
                .filter(order -> (SendCodeStatusEnum.SEND.getCode() == order.getSendCodeStatus() || SendCodeStatusEnum.RESEND.getCode()
                        == order.getSendCodeStatus()) && !order.getSendCodeIsSuccess())
                .collect(Collectors.toList());
    }

    private List<MerchantOrder> getNeedNewCodeOrders(List<MerchantOrder> merchantOrders) {
        return getMerchantOrdersBySendCodeStatus(merchantOrders, SendCodeStatusEnum.UN_SEND);
    }

    private List<MerchantOrder> getNeedReSendCodeOrders(List<MerchantOrder> merchantOrders) {
        return getMerchantOrdersBySendCodeStatus(merchantOrders, SendCodeStatusEnum.UN_RESEND);
    }

    private List<MerchantOrder> getMerchantOrdersBySendCodeStatus(List<MerchantOrder> merchantOrders,
                                                                  SendCodeStatusEnum sendCodeStatus) {
        if (CollectionUtils.isEmpty(merchantOrders)) {
            return Collections.emptyList();
        }
        return merchantOrders.stream()
                .filter(order -> sendCodeStatus.getCode() == order.getSendCodeStatus().intValue())
                .collect(Collectors.toList());
    }

    @Override
    public void resendCode(MerchantOrder order) {
        logger.info("重新发码开始  outerId={}, orderId={}", order.getOuterId(), order.getId());
        // 校验订单是否满足重新发码条件
        validateResendcodeOrder(order);
        // 重新发码
        List<Mcode> codes = codeService.listMcodeByOuterId(order.getOuterId());
        //过滤掉无效码
        codes = codes.stream().filter(code -> codeService.checkCodeAvailable(code)).collect(Collectors.toList());
        TransactionStatus status = transactionHelper.beginTransaction();
        try {
            //重置订单发码通知状态为未通知
            merchantOrderService.orderSendCodeNotifyReset(order.getId());
            // 记录码重发操作日志
            codeOperateLogService.saveCodeOperateLogs(codes, CodeOperateEnum.RESEND_CODE);
            // 订单重发码完成
            merchantOrderSendCodeLifeCycle.finishResendCode(order.getId());

            transactionHelper.commit(status);
        } catch (Exception ex) {
            logger.error("重新发码异常,数据回滚,outerId={}", order.getOuterId(), ex);
            transactionHelper.rollback(status);
            throw new BizSystemException(MashangExceptionEnum.SYSTEM_ERROR, ex);
        }
        // 通知码商平台
        resendNotifyCodeMerchantPlatform(order, codes);

        logger.info("重新发码结束  outerId={}, orderId={}", order.getOuterId(), order.getId());

    }

    private void resendNotifyCodeMerchantPlatform(MerchantOrder order, List<Mcode> codes) {
        //通知码商平台重新发码
        toTaobaoHelper.resend(order, codes);
        //更新订单发码成功
        merchantOrderService.orderSendCodeNotifySuccess(order.getId());
    }

    private void validateResendcodeOrder(MerchantOrder order) {
        if (order.getSendCodeStatus() != SendCodeStatusEnum.UN_RESEND.getCode()) {
            logger.info("订单[id={}]状态[status={}]不满足重新发码条件", order.getId(), order.getSendCodeStatus());
            throw new BizException(MashangExceptionEnum.ORDER_STATUS_CANNOT_RESEND_CODE);
        }
    }

    @Override
    public void acceptModifyValidity(ModifyValidityParam param) {
    	
        logger.info("修改订单[outerId={}]电子码有效期开始 param: {}", param.getOuterId(), JSON.toJSONString(param));

        MerchantOrder merchantOrder = merchantOrderService.getOrderByOuterId(param.getOuterId());
        //校验订单状态
        MerchantOrderUtil.validateOrderIsExpired(merchantOrder, param.getOuterId());
        //校验码是否有效
        validCodeIsExpired(merchantOrder.getOuterId());

        Mcode mcode = new Mcode();
        mcode.setOuterId(param.getOuterId());
        mcode.setValidStart(param.getValidStart());
        mcode.setValidEnd(param.getValidEnd());
        //之所以一起修改是因为同一个订单发布的多个码有效期都是一致的
        codeService.updateMcodeByOuterId(mcode);
        
        logger.info("修改订单[outerId={}]电子码有效期结束", param.getOuterId());
    }

    /**
     * 校验码是否过期
     * @param outerId
     */
	private void validCodeIsExpired(String outerId) {

		List<Mcode> mcodes = codeService.listMcodeByOuterId(outerId);
		if (CollectionUtils.isEmpty(mcodes)) {
			throw new BizException(MashangExceptionEnum.CODE_NOT_EXIST);
		}
		if (mcodes.get(0).getExpireStatus() == ExpireStatusEnum.EXPIRE.getCode()) {
			throw new BizException(MashangExceptionEnum.CODE_HAS_EXPIRED);
		}
		Date end = DateUtils.parse(DateUtils.YYYY_MM_DD_HMS, mcodes.get(0).getValidEnd());
		if (end.before(new Date())) {
			throw new BizException(MashangExceptionEnum.CODE_HAS_EXPIRED);
		}
	}

}
